#include <PlayerInterface.h>

#include <World.h>
#include <BaseObject.h>
#include <Camera.h>
#include <PhysicsObject.h>

#include <PlayerCommands.h>

#define IfHasPhysics \
	if(controlTarget && controlTarget->phys) 	

PlayerInterface::PlayerInterface(World& gameworld)
:world(gameworld)
,controlTarget(0)
,initialized(0)
,currentControlSet(0)
{
	External::player = this;
	
	moveSpeed = 5.0f;
	turnSpeed = 3.141592f * 0.5f;
	slowSpeed = 0.8f;

	walk_moveSpeed = 2.5f;
	walk_turnSpeed = 3.141592f * 0.015f;

	MAX_walk_moveSpeed = 5.0f;
	MAX_moveSpeed = 50.0f;
	MAX_turnSpeed = 3.141592f * 1.5f;
}

PlayerInterface::~PlayerInterface()
{
}

void PlayerInterface::Init()
{
	initialized = 1;
	RunOnce::GenerateControlSets();
	currentControlSet = &ControlSets::default_walk_controls;
}

void PlayerInterface::Update(float dt)
{
}
 
void PlayerInterface::Input(const bool* keys, float fps)
{
	if(!currentControlSet)
	{
		std::cerr<<"Error! No controls currently bound!\n";
		return;
	}

	std::map<unsigned char, void (*)(PlayerInterface&)>::iterator iter;
	iter = currentControlSet->begin();
	for(; iter != currentControlSet->end(); ++iter)
	{
		if( keys[ iter->first ] )
			iter->second(*this);
	}
}

void PlayerInterface::SetControlTarget(BaseObject* target)
{
	controlTarget = target;
	External::camera->SetTarget(target);
}

		
BaseObject* const PlayerInterface::GetControlTarget()
{
	return controlTarget;
}

////////////////////////////////////////////////////////////////////////
// controls
		
void PlayerInterface::MoveForward()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		vec2 dir = controlTarget->t.GetDir();
		vec2 vel = p->body->GetLinearVelocity();
		vel = vel + moveSpeed * dir;
		if( vel.Length() > MAX_moveSpeed )
			vel = MAX_moveSpeed * dir;
		p->body->SetLinearVelocity(vel);
		float ang = p->body->GetAngularVelocity();
		p->body->SetAngularVelocity(slowSpeed * ang);
	}
}

void PlayerInterface::TurnLeft()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		float ang = p->body->GetAngularVelocity();
		ang += turnSpeed;
		if( ang > MAX_turnSpeed )
			ang = MAX_turnSpeed;
		p->body->SetAngularVelocity(ang);
	}
}

void PlayerInterface::TurnRight()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		float ang = p->body->GetAngularVelocity();
		ang -= turnSpeed;
		if( ang < -MAX_turnSpeed )
			ang = -MAX_turnSpeed;
		p->body->SetAngularVelocity(ang);
	}
}

void PlayerInterface::Slow()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		vec2 v = p->body->GetLinearVelocity();
		if(v.Length() > 0.2f)
		{
			float ang = p->body->GetAngularVelocity();
			p->body->SetAngularVelocity(slowSpeed * ang);
			p->body->SetLinearVelocity(slowSpeed * v);
		}
		else
			Stop();
	}
}

void PlayerInterface::Stop()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		p->body->SetLinearVelocity(vec2(0,0));
		p->body->SetAngularVelocity(0);
	}
}


void PlayerInterface::Walk_MoveForward()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		vec2 dir = controlTarget->t.GetDir();
		vec2 vel = p->body->GetLinearVelocity();
		vel = vel + walk_moveSpeed * dir;
		if( vel.Length() > MAX_walk_moveSpeed )
			vel = MAX_walk_moveSpeed * dir;
		p->body->SetLinearVelocity(vel);
		p->body->SetAngularVelocity(0);
	}
}

void PlayerInterface::Walk_MoveBackward()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		vec2 dir = controlTarget->t.GetDir();
		vec2 vel = p->body->GetLinearVelocity();
		if( vel.Length() > 0.25f )
		{
			Slow();
		}
		else
		{
			Stop();
			vec2 pos = p->body->GetPosition();
			pos -= 0.1f * dir;
			p->body->SetTransform(pos, p->body->GetAngle());
		}
		//vel = vel - walk_moveSpeed * dir;
		//if( vel.Length() > MAX_walk_moveSpeed )
		//	vel = MAX_walk_moveSpeed * dir;
		//p->body->SetLinearVelocity(vel);
		p->body->SetAngularVelocity(0);
	}
}

void PlayerInterface::Walk_TurnLeft()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		float ang = p->body->GetAngle();
		ang += walk_turnSpeed;
		p->body->SetTransform( p->body->GetPosition(), ang );
		p->body->SetAngularVelocity(0);
	}
}

void PlayerInterface::Walk_TurnRight()
{
	IfHasPhysics
	{
		PhysicsObject* p = controlTarget->phys;
		float ang = p->body->GetAngle();
		ang -= walk_turnSpeed;
		p->body->SetTransform( p->body->GetPosition(), ang );
		p->body->SetAngularVelocity(0);
	}
}